package com.ruoyi.flow.core;

import com.ruoyi.flow.common.utils.RequestUtils;
import com.ruoyi.flow.core.exception.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Spring 全局异常处理器
 *
 * @author wtian
 * @version 1.0
 */
@Component
public class GlobalHandlerExceptionResolver implements HandlerExceptionResolver {
    private final static Log logger = LogFactory.getLog(GlobalHandlerExceptionResolver.class);

    @Override
    public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e) {
        String viewName = null;

        HandlerMethod handlerMethod = null;
        if (handler instanceof HandlerMethod) {
            handlerMethod = (HandlerMethod) handler;
        }

        // 业务型自定义异常
        int errStatus = 500;
        if (e instanceof BaseGuardException) {
            logger.warn(String.format("The request `%s` is an invalid operation: %s",
                    request.getRequestURL().toString(), e.toString()));


            if (e instanceof UnauthorizedException
                    || e instanceof NotPermittedException) {
                errStatus = HttpStatus.UNAUTHORIZED.value();
            } else if (e instanceof NotFoundException || e instanceof NonJsonResourceNotFoundException) {
                errStatus = HttpStatus.NOT_FOUND.value();
            } else if (e instanceof BadRequestException) {
                errStatus = HttpStatus.BAD_REQUEST.value();
            } else {
                errStatus = HttpStatus.INTERNAL_SERVER_ERROR.value();
            }
        }
        // ajax json response
        if (RequestUtils.isAjaxRequest(request)) {
            // 这里需要进行response是否committed判断
            // 因为：在快速触发ajax请求并存在abort(ajax)的情况下，服务器会cancel response，
            // 这个会造成 response.sendError() 失败，因为 response已经被cancelled了。
            if (!response.isCommitted()) {
                try {
                    response.sendError(errStatus, e.getMessage());
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
            return null;
        }

        if (isHtmlRequest(request, handlerMethod)) {
            viewName = String.valueOf(errStatus);
        }

        if (StringUtils.isEmpty(viewName) || "0".equals(viewName)) {
            logger.warn("GlobalHandlerExceptionResolver could not match any error<" + e.toString() + "> view, set `err.vm` to it as default.");
            viewName = "500";
        }

        ModelAndView errMv = new ModelAndView("error/" + viewName);
        errMv.addObject("error_msg", e.getMessage());

        return errMv;
    }


    /**
     * 判断一个请求是否是html试图请求
     */
    private static boolean isHtmlRequest(HttpServletRequest req, HandlerMethod handlerMethod) {
        String contentType = req.getHeader("Content-Type");
        return (contentType != null && contentType.indexOf("text/html") != -1)
                || (handlerMethod != null && handlerMethod.getMethod().getReturnType().equals(ModelAndView.class));
    }

}
